home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / vm / vmSubr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  43.4 KB  |  1,581 lines

  1. /* vmSubr.c -
  2.  *
  3.  *     This file contains miscellaneous virtual memory routines.
  4.  *
  5.  * Copyright (C) 1985 Regents of the University of California
  6.  * All rights reserved.
  7.  */
  8.  
  9. #ifndef lint
  10. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/vm/vmSubr.c,v 9.21 92/07/22 16:55:14 jhh Exp $ SPRITE (Berkeley)";
  11. #endif not lint
  12.  
  13. #include <sprite.h>
  14. #include <vm.h>
  15. #include <vmInt.h>
  16. #include <lock.h>
  17. #include <sync.h>
  18. #include <sys.h>
  19. #include <list.h>
  20. #include <dbg.h>
  21. #include <stdlib.h>
  22. #include <fs.h>
  23. #include <fsio.h>
  24. #include <stdio.h>
  25. #include <bstring.h>
  26. #include <assert.h>
  27. #include <vmHack.h>
  28. #ifdef sun4
  29. #include <machMon.h>
  30. #endif
  31. /*
  32.  * Declarations of external variables
  33.  */
  34.  
  35. Vm_Stat        vmStat;
  36. int             vmFirstFreePage;  
  37. Address        vmMemEnd;
  38. Sync_Lock     vmMonitorLock;
  39. Sync_Lock     vmShmLock;
  40. int        vmShmLockCnt = 0;
  41. int        vm_PageSize;
  42. int        vmPageShift;
  43. int        vmPageTableInc;
  44. int        vmKernMemSize;
  45. int        vmMaxProcesses = 80;
  46. Address        vmBlockCacheBaseAddr;
  47. Address     vmBlockCacheEndAddr;
  48. int        vmMaxMachSegs;
  49. extern Vm_SharedSegTable    sharedSegTable;
  50.  
  51. Boolean        vmDebugLargeAllocs = FALSE;
  52.  
  53. extern int debugVmStubs;    /* Unix compatibility flag. */
  54.  
  55. /*
  56.  * The maximum amount that a stack is allowed to grow.  We have to make it
  57.  * real big because of the current configuration of SPUR.  This can be made
  58.  * smaller once the exec stuff has changed.  Things are worse for the sun4
  59.  * due to the order in which user processes try to flush their register
  60.  * windows to a stack which hasn't been validated yet. 
  61.  *
  62.  * 12/19/1991
  63.  * Turns out things are bad all over because programs are getting more
  64.  * sloppy about their memory usage. Make the max growth size the same
  65.  * for all machines (8MB).  That should hold us for a few more years.
  66.  *
  67.  */
  68. #define    MAX_STACK_GROWTH_SIZE    (1024 * 1024 * 8)
  69. int        vmMaxStackPagesGrowth;
  70.  
  71. /*
  72.  * ----------------------------------------------------------------------------
  73.  *
  74.  * Vm_Init --
  75.  *
  76.  *     Initialize all virtual memory data structures.
  77.  *
  78.  * Results:
  79.  *     None.
  80.  *
  81.  * Side effects:
  82.  *     All virtual memory linked lists and arrays are initialized.
  83.  *
  84.  * ----------------------------------------------------------------------------
  85.  */
  86. void
  87. Vm_Init()
  88. {
  89.     register    Vm_PTE    *ptePtr;
  90.     int            i;
  91. #ifdef notdef
  92.     unsigned int    virtPage;
  93. #endif
  94.  
  95.     Sync_LockInitDynamic(&vmMonitorLock, "Vm:vmMonitorLock");
  96.     Sync_LockInitDynamic(&vmShmLock, "Vm:vmShmLock");
  97.  
  98.     /*
  99.      * Set up the maximum number of pages that a stack can grow.
  100.      */
  101.     vmMaxStackPagesGrowth = MAX_STACK_GROWTH_SIZE / vm_PageSize;
  102.     /*
  103.      * Partition up the kernel virtual address space.
  104.      */
  105.     vmStackBaseAddr = (Address) (mach_KernStart + vmKernMemSize);
  106.     vmStackEndAddr = vmStackBaseAddr + mach_KernStackSize * vmMaxProcesses;
  107.     vmMapBaseAddr = vmStackEndAddr;
  108.     vmMapBasePage = (unsigned int)vmMapBaseAddr / vm_PageSize;
  109.     vmMapEndAddr = vmMapBaseAddr + vmNumMappedPages * vm_PageSize;
  110.     vmMapEndPage = vmMapBasePage + vmNumMappedPages;
  111.     vmBlockCacheBaseAddr = VmMach_AllocKernSpace(vmMapEndAddr);
  112.     vmBlockCacheEndAddr = (Address)mach_KernEnd;
  113.     /*
  114.      * Allocate the segment table and core map.
  115.      */
  116.     VmSegTableAlloc();
  117.     VmCoreMapAlloc();
  118.     /*
  119.      * Initialize the structure for kernel stacks.
  120.      */
  121.     VmStackInit();
  122.     /*
  123.      * Allocate and initialize the kernel page table.
  124.      */
  125.     vm_SysSegPtr->ptSize = (mach_KernEnd - mach_KernStart) / vm_PageSize;
  126.     vm_SysSegPtr->ptPtr =
  127.         (Vm_PTE *)Vm_BootAlloc(sizeof(Vm_PTE) * vm_SysSegPtr->ptSize);
  128.  
  129.     bzero((Address)vm_SysSegPtr->ptPtr, sizeof(Vm_PTE) * vm_SysSegPtr->ptSize);
  130.  
  131.     /*
  132.      * Can no longer use Vm_BootAlloc
  133.      */
  134.     vmNoBootAlloc = TRUE;
  135.     vmBootEnd = vmMemEnd;
  136.     /* 
  137.      * Determine how many physical pages that we have used.
  138.      */
  139.     vmFirstFreePage = 
  140.     (unsigned int)(vmMemEnd - mach_KernStart - 1) / vm_PageSize + 1;
  141.  
  142.     for (i = 0, ptePtr = vm_SysSegPtr->ptPtr;
  143.      i < vmFirstFreePage;
  144.      i++, ptePtr++) {
  145.     *ptePtr = VM_VIRT_RES_BIT | VM_PHYS_RES_BIT | i;
  146.     }
  147.     /*
  148.      * Initialize the segment table and core map.
  149.      */
  150.     VmSegTableInit();
  151.     VmCoreMapInit();
  152. #ifdef notdef
  153.     /*
  154.      * Take away the page at the bottom of the kernel stack.
  155.      */
  156.     virtPage = (mach_StackBottom - mach_KernStart) >> vmPageShift;
  157.     vm_SysSegPtr->ptPtr[virtPage] = 0;
  158.     VmPutOnFreePageList(virtPage);
  159. #endif
  160.     /*
  161.      * Now call the hardware dependent initialization routine.
  162.      */
  163.     VmMach_Init(vmFirstFreePage);
  164.  
  165. #ifdef VM_CHECK_BSTRING_ACCESS
  166.     /* 
  167.      * Initialize the debugging structures in vmMap.c
  168.      */
  169.     VmMapInit();
  170. #endif
  171. }
  172.  
  173.  
  174. /*
  175.  * ----------------------------------------------------------------------------
  176.  *
  177.  * Vm_ProcInit --
  178.  *
  179.  *     Initialize VM info for this process.
  180.  *
  181.  * Results:
  182.  *     None.
  183.  *
  184.  * Side effects:
  185.  *     Virtual memory information for the given process is initialized.
  186.  *
  187.  * ----------------------------------------------------------------------------
  188.  */
  189. void
  190. Vm_ProcInit(procPtr)
  191.     Proc_ControlBlock    *procPtr;
  192. {
  193.     int                i;
  194.     register    Vm_ProcInfo    *vmPtr;
  195.  
  196.     if (procPtr->vmPtr == (Vm_ProcInfo *)NIL) {
  197.     vmPtr = (Vm_ProcInfo *)malloc(sizeof(Vm_ProcInfo));
  198.     vmPtr->machPtr = (VmMach_ProcData *)NIL;
  199.     procPtr->vmPtr = vmPtr;
  200.     } else {
  201.     vmPtr = procPtr->vmPtr;
  202.     }
  203.     for (i = 0; i < VM_NUM_SEGMENTS; i++) {
  204.     vmPtr->segPtrArray[i] = (Vm_Segment *)NIL;
  205.     }
  206.     vmPtr->vmFlags = 0;
  207.     vmPtr->numMakeAcc = 0;
  208.     vmPtr->sharedSegs = (List_Links *)NIL;
  209.     VmMach_ProcInit(vmPtr);
  210. }
  211.  
  212.  
  213. /*
  214.  *----------------------------------------------------------------------
  215.  *
  216.  * Vm_RawAlloc --
  217.  *
  218.  *    Allocate bytes of memory.
  219.  *
  220.  * Results:
  221.  *    Pointer to beginning of memory allocated..
  222.  *
  223.  * Side effects:
  224.  *    Variable that indicates the end of kernel memory is modified.
  225.  *
  226.  *----------------------------------------------------------------------
  227.  */
  228. ENTRY Address
  229. Vm_RawAlloc(numBytes)
  230. int numBytes;
  231. {
  232.     Address         retAddr;
  233.     Address         maxAddr;
  234.     int         lastPage;
  235.     Vm_PTE        *ptePtr;
  236.     Vm_VirtAddr        virtAddr;
  237.     register Vm_Segment    *segPtr;
  238.  
  239.     LOCK_MONITOR;
  240.  
  241.     /*
  242.      * We return the current end of memory as our new address.
  243.      */
  244.     if (numBytes > 100 * 1024) {
  245.     printf("\nvmMemEnd = 0x%x - ", vmMemEnd);
  246.     printf("Warning: VmRawAlloc asked for >100K\n");
  247.     if (vmDebugLargeAllocs) {
  248.         Sig_SendProc(Proc_GetEffectiveProc(), SIG_DEBUG, 0, (Address)0);
  249.     }
  250.     }
  251.     retAddr = vmMemEnd;
  252.  
  253.     /*
  254.      * Bump the end of memory by the number of bytes that we just
  255.      * allocated making sure that it is four byte aligned.
  256.      */
  257. #if defined(spur) || defined(sun4)
  258.     retAddr = (Address) (((unsigned)retAddr + 7) & ~7);
  259.     vmMemEnd += (numBytes + 7) & ~7;    /* eight byte aligned for SPUR. */
  260. #else
  261. #ifdef sequent
  262.     /*
  263.      * Need 16-byte alignment on Sequent Symmetry.  See comments in
  264.      * mem/memory.c for details.
  265.      */
  266.     retAddr = (Address) (((unsigned)retAddr + 0xf) & ~0xf);
  267.     vmMemEnd += (numBytes + 0xf) & ~0xf;
  268. #else
  269.     vmMemEnd += (numBytes + 3) & ~3;
  270. #endif    
  271. #endif
  272.  
  273.     /*
  274.      * Panic if we just ran off the end of memory.
  275.      */
  276.     if (vmMemEnd > (Address) ( mach_KernStart + vmKernMemSize)) {
  277.     printf("vmMemEnd = 0x%x - ", vmMemEnd);
  278.     panic("Vm_RawAlloc: Out of memory.\n");
  279.     }
  280.  
  281.     segPtr = vm_SysSegPtr;
  282.     virtAddr.segPtr = segPtr;
  283.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  284.     virtAddr.flags = 0;
  285.     lastPage = segPtr->numPages + segPtr->offset - 1;
  286.     maxAddr = (Address) ((lastPage + 1) * vm_PageSize - 1);
  287.     ptePtr = VmGetPTEPtr(segPtr, lastPage);
  288.  
  289.     /*
  290.      * Add new pages to the virtual address space until we have added
  291.      * enough to handle this memory request.  Note that we don't allow
  292.      * VmPageAllocateInt to block if it encounters lots of dirty pages.
  293.      */
  294.     while (vmMemEnd - 1 > maxAddr) {
  295.     int    page;
  296.  
  297.     maxAddr += vm_PageSize;
  298.     lastPage++;
  299.     VmIncPTEPtr(ptePtr, 1);
  300.     virtAddr.page = lastPage;
  301.     virtAddr.offset = 0;
  302.     page = VmPageAllocateInt(&virtAddr, 0);
  303.     if (page == VM_NO_MEM_VAL) {
  304.         /*
  305.          * The normal page allocation mechanism failed so go to the
  306.          * list of pages that are held in reserve for just such an
  307.          * occasion.
  308.          */
  309.         page = VmGetReservePage(&virtAddr);
  310.         if (page == VM_NO_MEM_VAL) {
  311.         panic("VmRawAlloc: No memory available\n");
  312.         }
  313.     }
  314.     *ptePtr |= page;
  315.     VmPageValidateInt(&virtAddr, ptePtr);
  316.     segPtr->numPages++;
  317.     }
  318.  
  319.     UNLOCK_MONITOR;
  320.  
  321.     return(retAddr);
  322. }
  323.  
  324. void ChangeCodeProt();
  325.  
  326.  
  327. /*
  328.  *----------------------------------------------------------------------
  329.  *
  330.  * Vm_ChangeCodeProt --
  331.  *
  332.  *    Change the protection of the code segment for the given process.  If
  333.  *    the process still has the shared code segment then make a new 
  334.  *    copy.
  335.  *
  336.  * Results:
  337.  *    None.
  338.  *
  339.  * Side effects:
  340.  *    None.
  341.  *
  342.  *----------------------------------------------------------------------
  343.  */
  344. void
  345. Vm_ChangeCodeProt(procPtr, startAddr, numBytes, makeWriteable)
  346.     Proc_ControlBlock        *procPtr;    /* Process to change code
  347.                          * protection for. */
  348.     Address                   startAddr;    /* Beginning address of range
  349.                          * of bytes to change
  350.                          * protection.*/
  351.     int                       numBytes;    /* Number of bytes to change
  352.                          * protection for. */
  353.     Boolean            makeWriteable;    /* TRUE => make the pages 
  354.                              *     writable.
  355.                              * FALSE => make readable only*/
  356. {
  357.     register    Vm_Segment    *segPtr;
  358.     Vm_Segment    *newSegPtr;
  359.     Fs_Stream            *codeFilePtr;
  360.  
  361.     segPtr = procPtr->vmPtr->segPtrArray[VM_CODE];
  362.     if (!(segPtr->flags & VM_DEBUGGED_SEG)) {
  363.     /*
  364.      * This process still has a hold of the original shared code 
  365.      * segment.  Make a new segment for the process.
  366.      */
  367.     Fsio_StreamCopy(segPtr->filePtr, &codeFilePtr);
  368.     newSegPtr = Vm_SegmentNew(VM_CODE, codeFilePtr, segPtr->fileAddr, 
  369.                   segPtr->numPages, segPtr->offset, procPtr);
  370.     Vm_ValidatePages(newSegPtr, newSegPtr->offset, 
  371.              newSegPtr->offset + newSegPtr->numPages - 1,
  372.              FALSE, TRUE);
  373.     } else {
  374.     newSegPtr = (Vm_Segment *)NIL;
  375.     }
  376.     ChangeCodeProt(procPtr, &newSegPtr, startAddr, numBytes, makeWriteable);
  377.     if (newSegPtr != (Vm_Segment *)NIL) {
  378.     Vm_SegmentDelete(newSegPtr, procPtr);
  379.     }
  380. }
  381.  
  382.  
  383. /*
  384.  *----------------------------------------------------------------------
  385.  *
  386.  * ChangeCodeProt --
  387.  *
  388.  *    Change the protection of the code segment for the given process.
  389.  *
  390.  * Results:
  391.  *    None.
  392.  *
  393.  * Side effects:
  394.  *    None.
  395.  *
  396.  *----------------------------------------------------------------------
  397.  */
  398. ENTRY void
  399. ChangeCodeProt(procPtr, segPtrPtr, startAddr, numBytes, makeWriteable)
  400.     Proc_ControlBlock        *procPtr;    /* Process to change protection
  401.                          * for. */
  402.     Vm_Segment            **segPtrPtr;    /* IN:  New duplicated segment
  403.                          * OUT: Segment to free if 
  404.                          *      non-NIL. */
  405.     Address                   startAddr;    /* Beginning address of range
  406.                          * of bytes to change
  407.                          * protection.*/
  408.     int                       numBytes;    /* Number of bytes to change
  409.                          * protection for. */
  410.     Boolean            makeWriteable;    /* TRUE => make the pages 
  411.                              *     writable.
  412.                              * FALSE => make readable only*/
  413. {
  414.     int                firstPage;
  415.     int                lastPage;
  416.     int                i;
  417.     register    Vm_PTE        *ptePtr;
  418.     register    Vm_Segment    *segPtr;
  419.  
  420.     LOCK_MONITOR;
  421.  
  422.     segPtr = procPtr->vmPtr->segPtrArray[VM_CODE];
  423.     if (!(segPtr->flags & VM_DEBUGGED_SEG)) {
  424.     /*
  425.      * This process is currently using the shared code segment.  Use the
  426.      * private copy that our caller allocated for us and return the 
  427.      * original segment so our caller can release its reference to it.
  428.      */
  429.     segPtr = *segPtrPtr;
  430.     segPtr->flags |= VM_DEBUGGED_SEG;
  431.     *segPtrPtr = procPtr->vmPtr->segPtrArray[VM_CODE];
  432.     procPtr->vmPtr->segPtrArray[VM_CODE] = segPtr;
  433.     /*
  434.      * Free up the hardware context for this process.  When it starts
  435.      * running again new context will be setup which will have
  436.      * the new code segment in it.
  437.      */
  438.     VmMach_FreeContext(procPtr);
  439.     }
  440.  
  441.     firstPage = (unsigned int) startAddr >> vmPageShift;
  442.     lastPage = ((unsigned int) (startAddr) + numBytes - 1) >> vmPageShift;
  443.     /* 
  444.      * Make sure that the range of addresses falls into the code segment's 
  445.      * page table.  If not don't do anything.
  446.      */
  447.     if (firstPage >= segPtr->offset &&
  448.     lastPage < segPtr->offset + segPtr->ptSize) {
  449.     for (i = lastPage - firstPage, ptePtr = VmGetPTEPtr(segPtr, firstPage);
  450.          i >= 0;
  451.          i--, VmIncPTEPtr(ptePtr, 1)) {
  452.         if (makeWriteable) {
  453.         *ptePtr &= ~VM_READ_ONLY_PROT;
  454.         } else {
  455.         *ptePtr |= VM_READ_ONLY_PROT;
  456.         }
  457.     }
  458.     VmMach_SetSegProt(segPtr, firstPage, lastPage, makeWriteable);
  459.     }
  460.  
  461.     UNLOCK_MONITOR;
  462. }
  463.  
  464.  
  465. /*
  466.  *----------------------------------------------------------------------
  467.  *
  468.  * Vm_ValidatePages --
  469.  *
  470.  *    Initialize the page table for the given segment.  This involves
  471.  *    going through the software page table in the range of pages given.
  472.  *
  473.  * Results:
  474.  *    None.
  475.  *
  476.  * Side effects:
  477.  *    Page table modified for the given segment.
  478.  *
  479.  *----------------------------------------------------------------------
  480.  */
  481.  
  482. ENTRY void
  483. Vm_ValidatePages(segPtr, firstPage, lastPage, zeroFill, clobber)
  484.     Vm_Segment     *segPtr;    /* The segment whose pages are being 
  485.                  * made valid. */
  486.     int        firstPage;    /* The first page to mark valid. */
  487.     int        lastPage;    /* The last page to mark valid. */
  488.     Boolean    zeroFill;    /* Should mark pages zero fill. */
  489.     Boolean    clobber;    /* TRUE -> overwrite the pte no matter what.
  490.                  * FALSE -> only overwrite if the pte is not
  491.                  *        marked as valid in this segment's
  492.                  *        virtual address space. */
  493. {
  494.     LOCK_MONITOR;
  495.  
  496.     VmValidatePagesInt(segPtr, firstPage, lastPage, zeroFill, clobber);
  497.  
  498.     UNLOCK_MONITOR;
  499. }
  500.  
  501.  
  502. /*
  503.  *----------------------------------------------------------------------
  504.  *
  505.  * VmValidatePagesInt --
  506.  *
  507.  *    Mark as virtually resident the range of pages in the page table.
  508.  *
  509.  * Results:
  510.  *    None.
  511.  *
  512.  * Side effects:
  513.  *    Page table modified for the given segment.
  514.  *
  515.  *----------------------------------------------------------------------
  516.  */
  517. INTERNAL void
  518. VmValidatePagesInt(segPtr,  firstPage, lastPage, zeroFill, clobber)
  519.     Vm_Segment     *segPtr;    /* The segment whose page table is being 
  520.                  * initialized. */
  521.     int        firstPage;    /* The first pte to be initialized */
  522.     int        lastPage;    /* The last pte to be initialized */
  523.     Boolean    zeroFill;    /* TRUE => Mark the page as zero fill. */
  524.     Boolean    clobber;    /* TRUE -> overwrite the pte no matter what.
  525.                  * FALSE -> only overwrite if the pte is not
  526.                  *        marked as valid in this segment's
  527.                  *        virtual address space. */
  528. {
  529.     register    int    i;
  530.     register    Vm_PTE    pte;
  531.     register    Vm_PTE    *ptePtr;
  532.  
  533.     pte = VM_VIRT_RES_BIT;
  534.     if (segPtr->type == VM_CODE) {
  535.     pte |= VM_READ_ONLY_PROT;
  536.     } else if (segPtr->type == VM_SHARED) {
  537.     if (segPtr->filePtr == (Fs_Stream *)NIL) {
  538.         pte |= VM_ON_SWAP_BIT;
  539.     }
  540.     } else if (zeroFill) {
  541.     pte |= VM_ZERO_FILL_BIT;
  542.     }
  543.     for (i = firstPage, ptePtr = VmGetPTEPtr(segPtr, firstPage);
  544.      i <= lastPage;
  545.      i++, ptePtr++) {
  546.     if (clobber || !(*ptePtr & VM_VIRT_RES_BIT)) {
  547.         *ptePtr = pte;
  548.     }
  549.     }
  550. }
  551.  
  552. #ifndef symm
  553.  
  554. /*
  555.  *----------------------------------------------------------------------
  556.  *
  557.  * VmZeroPage --
  558.  *
  559.  *    External routine to fill the entire given page frame with zeroes.
  560.  *
  561.  * Results:
  562.  *    None.
  563.  *
  564.  * Side effects:
  565.  *    The page is filled with zeroes.
  566.  *
  567.  *----------------------------------------------------------------------
  568.  */
  569. void
  570. VmZeroPage(pfNum)
  571.     unsigned int    pfNum;
  572. {
  573.     register    int    mappedAddr;
  574.  
  575.  
  576.     mappedAddr = (int) VmMapPage(pfNum);
  577.     bzero((Address) mappedAddr, vm_PageSize);
  578.     VmUnmapPage((Address) mappedAddr);
  579. }
  580. #endif /* !symm */
  581.  
  582.  
  583. /*
  584.  *----------------------------------------------------------------------
  585.  *
  586.  * VmVirtAddrParse --
  587.  *
  588.  *    Take the given virtual address and fill in a virtual address struct
  589.  *    with the segment, page, and offset for this address.  If it is 
  590.  *    determined in this routine that the address does not fall in any 
  591.  *    segment then the segment that is returned is NIL.
  592.  *
  593.  * Results:
  594.  *    The translated virtual address.
  595.  *
  596.  * Side effects:
  597.  *    If the virtual address falls into a stack or heap segment then the
  598.  *    heap segment for the process is prevented from being expanded.  This
  599.  *    is to prevent another process that is sharing the heap segment from
  600.  *    changing its size and making the parsed virtual address wrong.
  601.  *
  602.  *----------------------------------------------------------------------
  603.  */
  604. ENTRY void
  605. VmVirtAddrParse(procPtr, virtAddr, transVirtAddrPtr)
  606.     Proc_ControlBlock        *procPtr;
  607.     Address            virtAddr;
  608.     register    Vm_VirtAddr    *transVirtAddrPtr;
  609. {
  610.     register    Vm_Segment        *seg1Ptr;
  611.     register    Vm_Segment        *seg2Ptr;
  612.     Vm_SegProcList            *segProcPtr;
  613.     register    int            page;
  614.  
  615.     LOCK_SHM_MONITOR;
  616.     LOCK_MONITOR;
  617.  
  618.     assert(transVirtAddrPtr != (Vm_VirtAddr *) NIL && transVirtAddrPtr != 0);
  619. #ifdef sun4
  620.     if (!VMMACH_ADDR_CHECK(virtAddr)) {
  621.     transVirtAddrPtr->segPtr = (Vm_Segment *) NIL;
  622.     UNLOCK_MONITOR;
  623.     UNLOCK_SHM_MONITOR;
  624.     return;
  625.     }
  626. #endif
  627.     transVirtAddrPtr->flags = 0;
  628.     transVirtAddrPtr->sharedPtr = (Vm_SegProcList *) NIL;
  629.     if (VmMach_VirtAddrParse(procPtr, virtAddr, transVirtAddrPtr)) {
  630.     /*
  631.      * The hardware routine was able to translate it for us.
  632.      */
  633.     UNLOCK_MONITOR;
  634.     UNLOCK_SHM_MONITOR;
  635.     return;
  636.     }
  637.  
  638.     seg1Ptr = procPtr->vmPtr->segPtrArray[VM_HEAP];
  639.     assert(seg1Ptr != (Vm_Segment *) NIL);
  640.     assert(seg1Ptr != 0);
  641.  
  642.     while (seg1Ptr->flags & VM_PT_EXCL_ACC) {
  643.     Vm_Segment    *tSegPtr;
  644.     /*
  645.      * Wait while someone has exclusive access to the page tables.
  646.      */
  647.     tSegPtr = seg1Ptr;
  648.     (void)Sync_Wait(&tSegPtr->condition, FALSE);
  649.     }
  650.     transVirtAddrPtr->offset = (unsigned int)virtAddr & (vm_PageSize - 1);
  651.  
  652.     page = (unsigned int) (virtAddr) >> vmPageShift;
  653.     transVirtAddrPtr->page = page;
  654.     assert(procPtr != (Proc_ControlBlock *) NIL && procPtr != 0);
  655.     if (procPtr->vmPtr->sharedSegs != (List_Links *)NIL &&
  656.         virtAddr >= procPtr->vmPtr->sharedStart &&
  657.         virtAddr < procPtr->vmPtr->sharedEnd) {
  658.     dprintf("VmVirtAddrParse: Checking for address %x\n",virtAddr);
  659.     segProcPtr = VmFindSharedSegment(procPtr->vmPtr->sharedSegs,virtAddr);
  660.     if (segProcPtr != (Vm_SegProcList *)NIL) {
  661.         dprintf("VmVirtAddrParse: found address in seg %x\n",
  662.             segProcPtr->segTabPtr->segPtr->segNum);
  663.         transVirtAddrPtr->segPtr = segProcPtr->segTabPtr->segPtr;
  664.         transVirtAddrPtr->flags |= (segProcPtr->prot & VM_READONLY_SEG);
  665.         transVirtAddrPtr->sharedPtr = segProcPtr;
  666.         if (transVirtAddrPtr->flags & VM_READONLY_SEG) {
  667.         dprintf("VmVirtAddrParse: (segment is readonly)\n");
  668.         }
  669.         UNLOCK_MONITOR;
  670.         UNLOCK_SHM_MONITOR;
  671.         return;
  672.     }
  673.     }
  674.  
  675.     /*
  676.      * See if the address is too large to fit into the user's virtual
  677.      * address space.
  678.      */
  679.     if (page > mach_LastUserStackPage) {
  680.     transVirtAddrPtr->segPtr = (Vm_Segment *) NIL;
  681.     UNLOCK_MONITOR;
  682.     UNLOCK_SHM_MONITOR;
  683.     return;
  684.     }
  685.     seg2Ptr = procPtr->vmPtr->segPtrArray[VM_STACK];
  686.     /*
  687.      * Check the stack segment.  Anything past the end of the heap segment 
  688.      * falls into the stack segment.  Since page tables are not allowed to
  689.      * overlap, the end of the heap segment is defined to be the end of
  690.      * the heap page table.  If it falls in the stack segment then prevent
  691.      * this process's heap segment from being expanded by incrementing the
  692.      * in use count on the page table.
  693.      */
  694.     if (page > seg1Ptr->ptSize + seg1Ptr->offset) {
  695.     assert(seg2Ptr != (Vm_Segment *) NIL && seg2Ptr != 0);
  696.     if (page < seg2Ptr->offset) {
  697.         int    newPTSize;
  698.         newPTSize = ((mach_LastUserStackPage - page)/vmPageTableInc + 1) * 
  699.                                 vmPageTableInc;
  700.         /* 
  701.          * We are going to have to grow the stack to cover this so
  702.          * make sure that the heap and stack segments don't overlap and
  703.          * we aren't trying to grow too much.
  704.          */
  705.         if ((Address) (page << vmPageShift) < seg2Ptr->minAddr ||
  706.             seg2Ptr->offset - page > vmMaxStackPagesGrowth ||
  707.             seg1Ptr->offset + seg1Ptr->ptSize >=
  708.              mach_LastUserStackPage - newPTSize + 1) {
  709.         transVirtAddrPtr->segPtr = (Vm_Segment *) NIL;
  710.         UNLOCK_MONITOR;
  711.         UNLOCK_SHM_MONITOR;
  712.         return;
  713.         }
  714.     }
  715.     transVirtAddrPtr->segPtr = seg2Ptr;
  716.     transVirtAddrPtr->flags = VM_HEAP_PT_IN_USE;
  717.     seg1Ptr->ptUserCount++;
  718.     UNLOCK_MONITOR;
  719.     UNLOCK_SHM_MONITOR;
  720.     return;
  721.     }
  722.     /* 
  723.      * Check the heap segment.  If it falls in the heap segment then prevent
  724.      * the segment from being expanded.
  725.      */
  726.     if (page >= seg1Ptr->offset && 
  727.         page < (seg1Ptr->offset + seg1Ptr->numPages)) {
  728.  
  729.     transVirtAddrPtr->segPtr = seg1Ptr;
  730.     transVirtAddrPtr->flags = VM_HEAP_PT_IN_USE;
  731.     seg1Ptr->ptUserCount++;
  732.     UNLOCK_MONITOR;
  733.     UNLOCK_SHM_MONITOR;
  734.     return;
  735.     }
  736.  
  737.     /*
  738.      * Check the code segment.
  739.      */
  740.     seg1Ptr = procPtr->vmPtr->segPtrArray[VM_CODE];
  741.     if (page >= seg1Ptr->offset &&
  742.         page < (seg1Ptr->offset + seg1Ptr->numPages)) {
  743.     transVirtAddrPtr->segPtr = seg1Ptr;
  744.     UNLOCK_MONITOR;
  745.     UNLOCK_SHM_MONITOR;
  746.     return;
  747.     }
  748.  
  749.     /*
  750.      * Doesn't fall in any segment so return NIL.
  751.      */
  752.     transVirtAddrPtr->segPtr = (Vm_Segment *) NIL;
  753.     UNLOCK_MONITOR;
  754.     UNLOCK_SHM_MONITOR;
  755.     return;
  756. }
  757.  
  758.  
  759. /*
  760.  *----------------------------------------------------------------------
  761.  *
  762.  * VmCheckBounds --
  763.  *
  764.  *    See if the given virtual address falls within the bounds of the
  765.  *    segment.  It is assumed that this segment is prevented from being
  766.  *    expanded.
  767.  *
  768.  * Results:
  769.  *    TRUE if the virtual address is in bounds.
  770.  *
  771.  * Side effects:
  772.  *    None.
  773.  *
  774.  *----------------------------------------------------------------------
  775.  */
  776. Boolean
  777. VmCheckBounds(virtAddrPtr)
  778.     register    Vm_VirtAddr    *virtAddrPtr;
  779. {
  780.     register    Vm_Segment    *segPtr;
  781.  
  782.     segPtr = virtAddrPtr->segPtr;
  783.     if (segPtr == (Vm_Segment *) NIL) {
  784.     dprintf("VmCheckBounds: NIL failure\n");
  785.     return(FALSE);
  786.     }
  787.     if (segPtr->type == VM_STACK) {
  788.     return(virtAddrPtr->page > mach_LastUserStackPage - segPtr->numPages);
  789.     } else {
  790.     if (virtAddrPtr->page - segOffset(virtAddrPtr) < 0 ||
  791.         virtAddrPtr->page - segOffset(virtAddrPtr) >
  792.         virtAddrPtr->segPtr->ptSize) {
  793.         printf("VmCheckBounds: out of bounds: page %x offset %x\n",
  794.             virtAddrPtr->page, segOffset(virtAddrPtr));
  795.         return(FALSE);
  796.     }
  797. #if 0
  798.     if (!((*VmGetAddrPTEPtr(virtAddrPtr,virtAddrPtr->page)) &
  799.         VM_VIRT_RES_BIT)) {
  800.         dprintf("VmCheckBounds: page absent failure\n");
  801.     }
  802. #endif
  803.     return ((*VmGetAddrPTEPtr(virtAddrPtr,virtAddrPtr->page)) &
  804.         VM_VIRT_RES_BIT);
  805.     }
  806. }
  807.  
  808. /*
  809.  *----------------------------------------------------------------------
  810.  *
  811.  * Vm_CopyInProc --
  812.  *
  813.  *    Copy from another processes address space into the current address
  814.  *    space. It assumed that this routine is called with the source 
  815.  *    process locked such that its VM will not go away while we are doing
  816.  *    this copy.
  817.  *
  818.  * Results:
  819.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  820.  *
  821.  * Side effects:
  822.  *    What toAddr points to is modified.
  823.  *
  824.  *----------------------------------------------------------------------
  825.  */
  826. ReturnStatus
  827. Vm_CopyInProc(numBytes, fromProcPtr, fromAddr, toAddr, toKernel)
  828.     int                numBytes;    /* The maximum number of bytes
  829.                          * to copy in. */
  830.     register Proc_ControlBlock    *fromProcPtr;    /* Which process to copy from.*/
  831.     Address            fromAddr;    /* The address to copy from */
  832.     Address            toAddr;        /* The address to copy to */
  833.     Boolean            toKernel;    /* This copy is happening to 
  834.                          * the kernel's address space.*/
  835. {
  836.     ReturnStatus        status = SUCCESS;
  837.     Vm_VirtAddr            transVirtAddr;
  838.     int                lastPage;
  839.     register Proc_ControlBlock    *toProcPtr;
  840.     register Vm_Segment        **toSegPtrArr;
  841.     register int        genFlags;
  842.  
  843.     if (fromProcPtr->genFlags & PROC_NO_VM) {
  844.     /*
  845.      * The process that we are copying from has already deleted its VM.
  846.      */
  847.     return(SYS_ARG_NOACCESS);
  848.     }
  849.     toProcPtr = Proc_GetCurrentProc();
  850.     if (toProcPtr->genFlags & PROC_KERNEL) {
  851. #ifdef notdef
  852.     if (!toKernel) {
  853.         panic("Vm_CopyInProc: Kernel process not copying to kernel\n");
  854.     }
  855. #endif
  856.  
  857.     /*
  858.      * We are copying to a kernel process (an rpc server process
  859.      * hopefully).  Since we know that the process that we are copying
  860.      * from can't exit until we finish this copy we can borrow
  861.      * its address space and then just do a normal copy in.
  862.      */
  863.     toSegPtrArr = toProcPtr->vmPtr->segPtrArray;
  864.     toSegPtrArr[VM_CODE] = fromProcPtr->vmPtr->segPtrArray[VM_CODE];
  865.     toSegPtrArr[VM_HEAP] = fromProcPtr->vmPtr->segPtrArray[VM_HEAP];
  866.     toSegPtrArr[VM_STACK] = fromProcPtr->vmPtr->segPtrArray[VM_STACK];
  867.     Proc_Lock(toProcPtr);
  868.     genFlags = toProcPtr->genFlags;
  869.     genFlags &= ~PROC_KERNEL;
  870.     genFlags |= PROC_USER;
  871.     toProcPtr->genFlags = genFlags;
  872.     Proc_Unlock(toProcPtr);
  873.     VmMach_ReinitContext(toProcPtr);
  874.     status = Vm_CopyIn(numBytes, fromAddr, toAddr);
  875.     /*
  876.      * Change back into a kernel process.
  877.      */
  878.     Proc_Lock(toProcPtr);
  879.     genFlags = toProcPtr->genFlags;
  880.     genFlags &= ~PROC_USER;
  881.     genFlags |= PROC_KERNEL;
  882.     toProcPtr->genFlags = genFlags;
  883.     Proc_Unlock(toProcPtr);
  884.     toSegPtrArr[VM_CODE] = (Vm_Segment *)NIL;
  885.     toSegPtrArr[VM_HEAP] = (Vm_Segment *)NIL;
  886.     toSegPtrArr[VM_STACK] = (Vm_Segment *)NIL;
  887.     VmMach_ReinitContext(toProcPtr);
  888.     return(status);
  889.     }
  890.  
  891.     if (!toKernel && (toAddr < mach_FirstUserAddr ||
  892.                       toAddr > mach_LastUserAddr ||
  893.               toAddr + numBytes - 1 > mach_LastUserAddr)) {
  894.     /*
  895.      * The dest address is definitely not in this user process's address
  896.      * space.
  897.      */
  898.     return(SYS_ARG_NOACCESS);
  899.     }
  900.     /*
  901.      * Determine which segment the address falls into.
  902.      */
  903.     VmVirtAddrParse(fromProcPtr, fromAddr, &transVirtAddr);
  904.     if (transVirtAddr.segPtr == (Vm_Segment *)NIL) {
  905.     return(SYS_ARG_NOACCESS);
  906.     }
  907.     /*
  908.      * We now have the segment that the first address falls into, now make
  909.      * sure that the end address falls in there as well.
  910.      */
  911.     lastPage = ((unsigned int)fromAddr + numBytes - 1) / vm_PageSize;
  912.     if (transVirtAddr.segPtr->type == VM_STACK) {
  913.     if (lastPage > mach_LastUserStackPage) {
  914.         status = SYS_ARG_NOACCESS;
  915.         goto exit;
  916.     }
  917.     } else {
  918.     if (lastPage >= 
  919.         segOffset(&transVirtAddr) + transVirtAddr.segPtr->numPages) {
  920.         status = SYS_ARG_NOACCESS;
  921.         goto exit;
  922.     }
  923.     }
  924.     /*
  925.      * Call the hardware dependent routine to do the copy.
  926.      */
  927.     status = VmMach_CopyInProc(numBytes, fromProcPtr, fromAddr,
  928.                                &transVirtAddr, toAddr, toKernel);
  929.  
  930. exit:
  931.     /*
  932.      * If the source segment was a stack or heap segment then the heap
  933.      * segment was prevented from being expanded.  Let it be expanded now.
  934.      */
  935.     if (transVirtAddr.flags & VM_HEAP_PT_IN_USE) {
  936.     VmDecPTUserCount(fromProcPtr->vmPtr->segPtrArray[VM_HEAP]);
  937.     }
  938.     return(status);
  939. }
  940.  
  941.  
  942. /*
  943.  *----------------------------------------------------------------------
  944.  *
  945.  * Vm_CopyOutProc --
  946.  *
  947.  *    Copy from the current VAS to another processes VAS.  It assumed that
  948.  *    this routine is called with the dest process locked such that its 
  949.  *    VM will not go away while we are doing the copy.
  950.  *
  951.  * Results:
  952.  *    SUCCESS if the copy succeeded, SYS_ARG_NOACCESS if fromAddr is invalid.
  953.  *
  954.  * Side effects:
  955.  *    What toAddr points to is modified.
  956.  *
  957.  *----------------------------------------------------------------------
  958.  */
  959. ReturnStatus
  960. Vm_CopyOutProc(numBytes, fromAddr, fromKernel, toProcPtr, toAddr)
  961.     int                numBytes;    /* The maximum number of bytes
  962.                          * to copy in. */
  963.     Address            fromAddr;    /* The address to copy from */
  964.     Boolean            fromKernel;    /* This copy is happening to
  965.                          * the kernel's address space.*/
  966.     register Proc_ControlBlock    *toProcPtr;    /* Which process to copy from.*/
  967.     Address            toAddr;        /* The address to copy to */
  968. {
  969.     ReturnStatus        status = SUCCESS;
  970.     Vm_VirtAddr            transVirtAddr;
  971.     int                lastPage;
  972.     register Vm_Segment        *segPtr;
  973.     register Proc_ControlBlock    *fromProcPtr;
  974.     register Vm_Segment        **fromSegPtrArr;
  975.     register int        genFlags;
  976.  
  977.     if (toProcPtr->genFlags & PROC_NO_VM) {
  978.     /*
  979.      * The process that we are copying to has already deleted its VM.
  980.      */
  981.     return(SYS_ARG_NOACCESS);
  982.     }
  983.     fromProcPtr = Proc_GetCurrentProc();
  984.  
  985.     if (fromProcPtr->genFlags & PROC_KERNEL) {
  986. #ifdef notdef
  987.     if (!fromKernel) {
  988.         panic("Vm_CopyOutProc: Kernel process not copying from kernel\n");
  989.     }
  990. #endif
  991.  
  992.     /*
  993.      * We are copying to a kernel process (an rpc server process
  994.      * hopefully).  Since we know that the process that we are copying
  995.      * from can't exit until we finish this copy we can borrow
  996.      * its address space and then just do a normal copy in.
  997.      */
  998.     fromSegPtrArr = fromProcPtr->vmPtr->segPtrArray;
  999.     fromSegPtrArr[VM_CODE] = toProcPtr->vmPtr->segPtrArray[VM_CODE];
  1000.     fromSegPtrArr[VM_HEAP] = toProcPtr->vmPtr->segPtrArray[VM_HEAP];
  1001.     fromSegPtrArr[VM_STACK] = toProcPtr->vmPtr->segPtrArray[VM_STACK];
  1002.     Proc_Lock(fromProcPtr);
  1003.     genFlags = fromProcPtr->genFlags;
  1004.     genFlags &= ~PROC_KERNEL;
  1005.     genFlags |= PROC_USER;
  1006.     fromProcPtr->genFlags = genFlags;
  1007.     Proc_Unlock(fromProcPtr);
  1008.     VmMach_ReinitContext(fromProcPtr);
  1009.     status = Vm_CopyOut(numBytes, fromAddr, toAddr);
  1010.     /*
  1011.      * Change back into a kernel process.
  1012.      */
  1013.     Proc_Lock(fromProcPtr);
  1014.     genFlags = fromProcPtr->genFlags;
  1015.     genFlags &= ~PROC_USER;
  1016.     genFlags |= PROC_KERNEL;
  1017.     fromProcPtr->genFlags = genFlags;
  1018.     Proc_Unlock(fromProcPtr);
  1019.     fromSegPtrArr[VM_CODE] = (Vm_Segment *)NIL;
  1020.     fromSegPtrArr[VM_HEAP] = (Vm_Segment *)NIL;
  1021.     fromSegPtrArr[VM_STACK] = (Vm_Segment *)NIL;
  1022.     VmMach_ReinitContext(fromProcPtr);
  1023.     return(status);
  1024.     }
  1025.  
  1026.     if (fromProcPtr->genFlags & PROC_NO_VM) {
  1027.     /*
  1028.      * The process that we are copying from has already deleted its VM.
  1029.      */
  1030.     if (!fromKernel) {
  1031.         return(SYS_ARG_NOACCESS);
  1032.     }
  1033.     }
  1034.     /*
  1035.      * Determine which segment the address falls into.
  1036.      */
  1037.     VmVirtAddrParse(toProcPtr, toAddr, &transVirtAddr);
  1038.     if (transVirtAddr.segPtr == (Vm_Segment *)NIL) {
  1039.     return(SYS_ARG_NOACCESS);
  1040.     }
  1041.     segPtr = transVirtAddr.segPtr;
  1042.     /*
  1043.      * We now have the segment that the first address falls into, now make
  1044.      * sure that the end address falls in there as well.
  1045.      */
  1046.     lastPage = ((unsigned int)toAddr + numBytes - 1) / vm_PageSize;
  1047.     if (segPtr->type == VM_STACK) {
  1048.     if (lastPage > mach_LastUserStackPage) {
  1049.         status = SYS_ARG_NOACCESS;
  1050.         goto exit;
  1051.     }
  1052.     } else {
  1053.     if (lastPage >= segOffset(&transVirtAddr) + segPtr->numPages) {
  1054.         status = SYS_ARG_NOACCESS;
  1055.         goto exit;
  1056.     }
  1057.     }
  1058.     status = VmMach_CopyOutProc(numBytes, fromAddr, fromKernel, toProcPtr, 
  1059.                 toAddr, &transVirtAddr);
  1060.  
  1061. exit:
  1062.     /*
  1063.      * If the dest segment was a stack or heap segment then the heap
  1064.      * segment was prevented from being expanded.  Let it be expanded now.
  1065.      */
  1066.     if (transVirtAddr.flags & VM_HEAP_PT_IN_USE) {
  1067.     VmDecPTUserCount(toProcPtr->vmPtr->segPtrArray[VM_HEAP]);
  1068.     }
  1069.     return(status);
  1070. }
  1071.  
  1072.  
  1073. /*
  1074.  *----------------------------------------------------------------------
  1075.  *
  1076.  * Vm_GetKernPageFrame --
  1077.  *
  1078.  *    Return the kernel virtual page frame that is valid at the given virtual
  1079.  *    page number.  Intended to be used by the hardware specific module.
  1080.  *
  1081.  * Results:
  1082.  *    Kernel page from the page table entry.
  1083.  *
  1084.  * Side effects:
  1085.  *    None.
  1086.  *
  1087.  *----------------------------------------------------------------------
  1088.  */
  1089. unsigned int
  1090. Vm_GetKernPageFrame(pageFrame)
  1091.     int    pageFrame;
  1092. {
  1093.     Vm_PTE    *ptePtr;
  1094.     ptePtr = VmGetPTEPtr(vm_SysSegPtr, pageFrame);
  1095.     return(Vm_GetPageFrame(*ptePtr));
  1096. }
  1097.  
  1098.  
  1099. /*
  1100.  *----------------------------------------------------------------------
  1101.  *
  1102.  * Vm_KernPageAllocate --
  1103.  *
  1104.  *    Return a physical page frame.  Intended to be used by the hardware
  1105.  *    specific module.
  1106.  *
  1107.  * Results:
  1108.  *    Virtual page frame.
  1109.  *
  1110.  * Side effects:
  1111.  *    Page is taken out of the page pool.
  1112.  *
  1113.  *----------------------------------------------------------------------
  1114.  */
  1115. unsigned int
  1116. Vm_KernPageAllocate()
  1117. {
  1118.     Vm_VirtAddr    virtAddr;
  1119.  
  1120.     virtAddr.sharedPtr = (Vm_SegProcList *) NIL;
  1121.     virtAddr.segPtr = vm_SysSegPtr;
  1122.     virtAddr.page = 0;
  1123.     return(VmPageAllocate(&virtAddr, VM_CAN_BLOCK));
  1124. }
  1125.  
  1126.  
  1127. /*
  1128.  *----------------------------------------------------------------------
  1129.  *
  1130.  * Vm_KernPageFree --
  1131.  *
  1132.  *    Free the page frame that was returned from Vm_KernPageAlloc.
  1133.  *
  1134.  * Results:
  1135.  *    None.
  1136.  *
  1137.  * Side effects:
  1138.  *    Page freed.
  1139.  *
  1140.  *----------------------------------------------------------------------
  1141.  */
  1142. void
  1143. Vm_KernPageFree(pfNum)
  1144.     unsigned    int    pfNum;
  1145. {
  1146.     VmPageFree(pfNum);
  1147. }
  1148.  
  1149.  
  1150. /*
  1151.  *----------------------------------------------------------------------
  1152.  *
  1153.  * Vm_FlushCode --
  1154.  *
  1155.  *    Flush the code at the given address from the code cache.
  1156.  *
  1157.  * Results:
  1158.  *    None.
  1159.  *
  1160.  * Side effects:
  1161.  *    None.
  1162.  *
  1163.  *----------------------------------------------------------------------
  1164.  */
  1165. ENTRY void
  1166. Vm_FlushCode(procPtr, addr, numBytes)
  1167.     Proc_ControlBlock    *procPtr;
  1168.     Address        addr;
  1169.     int            numBytes;
  1170. {
  1171.     Vm_VirtAddr    virtAddr;
  1172.     Vm_PTE    *ptePtr;
  1173.     int        lastPage;
  1174.     int        toFlush;
  1175.  
  1176.     LOCK_MONITOR;
  1177.  
  1178.     virtAddr.segPtr = procPtr->vmPtr->segPtrArray[VM_CODE];
  1179.     virtAddr.sharedPtr = (Vm_SegProcList *)NIL;
  1180.     virtAddr.page = (unsigned)addr >> vmPageShift;
  1181.     virtAddr.offset = (unsigned)addr & (vm_PageSize - 1);
  1182.     virtAddr.flags = 0;
  1183.     lastPage = ((unsigned)addr + numBytes - 1) >> vmPageShift;
  1184.     if (virtAddr.page >= virtAddr.segPtr->offset && 
  1185.         lastPage < virtAddr.segPtr->offset + virtAddr.segPtr->numPages) {
  1186.  
  1187.     for (ptePtr = VmGetPTEPtr(virtAddr.segPtr, virtAddr.page);
  1188.          virtAddr.page <= lastPage;
  1189.          virtAddr.page++, VmIncPTEPtr(ptePtr, 1)) {
  1190.         toFlush = vm_PageSize - virtAddr.offset;
  1191.         if (toFlush > numBytes) {
  1192.         toFlush = numBytes;
  1193.         }
  1194.         if (*ptePtr & VM_PHYS_RES_BIT) {
  1195.         VmMach_FlushCode(procPtr, &virtAddr, 
  1196.             (unsigned)(*ptePtr & VM_PAGE_FRAME_FIELD), toFlush);
  1197.         }
  1198.         numBytes -= toFlush;
  1199.         virtAddr.offset = 0;
  1200.     }
  1201.     }
  1202.  
  1203.     UNLOCK_MONITOR;
  1204. }
  1205.  
  1206.  
  1207. /*
  1208.  *----------------------------------------------------------------------
  1209.  *
  1210.  * VmFindSharedSegment --
  1211.  *
  1212.  *    Take the given virtual address and find which shared segment
  1213.  *    the address falls into.  If the address does not fall in any 
  1214.  *    shared segment then the segment that is returned is NIL.
  1215.  *
  1216.  * Results:
  1217.  *    The pointer to the shared segment list entry is returned,
  1218.  *    or NIL if none found.
  1219.  *
  1220.  * Side effects:
  1221.  *    None.
  1222.  *
  1223.  *----------------------------------------------------------------------
  1224.  */
  1225. Vm_SegProcList *
  1226. VmFindSharedSegment(sharedSegs, virtAddr)
  1227.     List_Links             *sharedSegs;
  1228.     Address            virtAddr;
  1229. {
  1230.     Vm_SegProcList    *segLinkPtr;
  1231.  
  1232.     int i=0;
  1233.  
  1234.     /*
  1235.      * Check the shared segment list.
  1236.      */
  1237.     CHECK_SHM_MONITOR;
  1238.     LIST_FORALL(sharedSegs, (List_Links *) segLinkPtr) {
  1239.     i++;
  1240.     if (i>20) {
  1241.         dprintf("VmFindSharedSegment: loop!\n");
  1242.         break;
  1243.     }
  1244.     if (segLinkPtr->mappedStart <= virtAddr &&
  1245.         virtAddr <= segLinkPtr->mappedEnd) {
  1246.         dprintf("VmFindSharedSegment: Address is in shared segment range\n");
  1247.         return segLinkPtr;
  1248.     } else {
  1249.         dprintf("VmFindSharedSegment: Address %x outside %x %x\n",
  1250.             (int)virtAddr, (int)segLinkPtr->mappedStart,
  1251.             (int)segLinkPtr->mappedEnd);
  1252.     }
  1253.     }
  1254.     return (Vm_SegProcList *)NIL;
  1255. }
  1256.  
  1257. /*
  1258.  *----------------------------------------------------------------------
  1259.  *
  1260.  * Vm_CleanupSharedProc --
  1261.  *
  1262.  *    Remove a process's shared memory structures, for when the
  1263.  *    process exits.
  1264.  *
  1265.  * Results:
  1266.  *    None.
  1267.  *
  1268.  * Side effects:
  1269.  *    Shared memory structures associated with the process are deleted.
  1270.  *    
  1271.  *
  1272.  *----------------------------------------------------------------------
  1273.  */
  1274. void
  1275. Vm_CleanupSharedProc(procPtr)
  1276.     Proc_ControlBlock    *procPtr;    /* Process that is exiting. */
  1277. {
  1278.     int i=0;
  1279.     List_Links    *sharedSegs;    /* Process's shared segments. */
  1280.  
  1281.     LOCK_SHM_MONITOR;
  1282.     sharedSegs = procPtr->vmPtr->sharedSegs;
  1283.     while (sharedSegs != (List_Links *)NIL) {
  1284.     if (sharedSegs == (List_Links *)NULL) {
  1285.         dprintf("Vm_CleanupSharedProc: warning: sharedSegs == NULL\n");
  1286.         break;
  1287.     }
  1288.     i++;
  1289.     if (i>20) {
  1290.         dprintf("Vm_CleanupSharedProc: procExit: segment loop!\n");
  1291.         break;
  1292.     }
  1293.     if (sharedSegs==(List_Links *)NULL) {
  1294.         printf("Vm_CleanupSharedProc: Danger: null sharedSegs list\n");
  1295.         break;
  1296.     }
  1297.     if (List_IsEmpty(sharedSegs)) {
  1298.         printf("Vm_CleanupSharedProc: Danger: empty sharedSegs list\n");
  1299.         break;
  1300.     }
  1301.     if (List_First(sharedSegs)==
  1302.         (List_Links *)NULL) {
  1303.         break;
  1304.     }
  1305.     Vm_DeleteSharedSegment(procPtr,
  1306.         (Vm_SegProcList *)List_First(sharedSegs));
  1307.     }
  1308.     UNLOCK_SHM_MONITOR;
  1309. }
  1310.  
  1311. /*
  1312.  *----------------------------------------------------------------------
  1313.  *
  1314.  * Vm_DeleteSharedSegment --
  1315.  *
  1316.  *    Remove a process's mapping of a shared segment.
  1317.  *
  1318.  *      This routine removes segProcPtr from the list of shared segment
  1319.  *      mappings and frees the structure.
  1320.  *    If the process has no more references to the segment,
  1321.  *    Vm_SegmentDelete is called on the segment.  If there are no more
  1322.  *    references to the segment, it is removed from the list of shared
  1323.  *    segments.  If the process has no more shared segments, its shared
  1324.  *    segment list is freed.
  1325.  *
  1326.  * Results:
  1327.  *    None.
  1328.  *
  1329.  * Side effects:
  1330.  *    References to the segment mapping are removed.  Any unneeded data
  1331.  *    structures are unlinked and freed.
  1332.  *
  1333.  *----------------------------------------------------------------------
  1334.  */
  1335. void
  1336. Vm_DeleteSharedSegment(procPtr,segProcPtr)
  1337.     Proc_ControlBlock    *procPtr;    /* Process with mapping. */
  1338.     Vm_SegProcList        *segProcPtr;    /* Pointer to segment mapping. */
  1339. {
  1340.     Vm_SharedSegTable    *segTabPtr = segProcPtr->segTabPtr;
  1341.     Vm_Segment        *segPtr;
  1342.     Vm_VirtAddr        virtAddr;
  1343.     int            done = 0;
  1344.  
  1345.     CHECK_SHM_MONITOR;
  1346.     LOCK_MONITOR;
  1347.     virtAddr.page = ((int)segProcPtr->mappedStart) >> vmPageShift;
  1348.     virtAddr.segPtr = segTabPtr->segPtr;
  1349.     virtAddr.sharedPtr = segProcPtr;
  1350.     UNLOCK_MONITOR;
  1351.  
  1352.     (void) VmPageFlush(&virtAddr, segProcPtr->mappedEnd -
  1353.         segProcPtr->mappedStart + 1, FALSE, FALSE);
  1354.     List_Remove((List_Links *)segProcPtr);
  1355.     VmMach_SharedSegFinish(procPtr,segProcPtr->addr);
  1356.     if (debugVmStubs) {
  1357.     printf("Vm_DeleteSharedSegment: freeing segProcPtr %x\n", segProcPtr);
  1358.     }
  1359.     free((Address)segProcPtr);
  1360.     /*
  1361.      * Check if this is the process's last reference to the segment.
  1362.      */
  1363.     segPtr = segTabPtr->segPtr;
  1364.     segTabPtr->refCount--;
  1365.     if (segTabPtr->refCount == 0) {
  1366.     done = 1;
  1367.     }
  1368.     if (!VmCheckSharedSegment(procPtr,segPtr)){
  1369.     dprintf("Vm_DeleteSharedSegment: Process has no more references to segment\n");
  1370.     if (List_IsEmpty(procPtr->vmPtr->sharedSegs)) {
  1371.         dprintf("Vm_DeleteSharedSegment: Process has no more shared segments\n");
  1372.         VmMach_SharedProcFinish(procPtr);
  1373.         free((Address)procPtr->vmPtr->sharedSegs);
  1374.         procPtr->vmPtr->sharedSegs = (List_Links *)NIL;
  1375.     }
  1376.     /*
  1377.      * Don't want Vm_SegmentDelete to destroy swap file unless we're
  1378.      * through with it.
  1379.      * Now I think that Vm_SegmentDelete will do the right thing even
  1380.      * without this, but I'm leaving it in just in case - Ken 10/91.
  1381.      */
  1382.     if (!done) {
  1383.         segPtr->flags &= ~VM_SWAP_FILE_OPENED;
  1384.     }
  1385.     Vm_SegmentDelete(segPtr,procPtr);
  1386.     if (!done) {
  1387.         dprintf("Vm_DeleteSharedSegment: Restoring VM_SWAP_FILE_OPENED\n");
  1388.         segPtr->flags |= VM_SWAP_FILE_OPENED;
  1389.     }
  1390.     }
  1391.     VmPrintSharedSegs(procPtr);
  1392.     dprintf("Vm_DeleteSharedSegment: done\n");
  1393.  
  1394. }
  1395.  
  1396. /*
  1397.  *----------------------------------------------------------------------
  1398.  *
  1399.  * VmCheckSharedSegment --
  1400.  *
  1401.  *    See if a process has the shared segment mapped.
  1402.  *
  1403.  * Results:
  1404.  *    TRUE if the shared segment is mapped by the process.
  1405.  *    FALSE otherwise.
  1406.  *
  1407.  * Side effects:
  1408.  *    Reads the shared memory data, so the SHM lock must be held.
  1409.  *
  1410.  *----------------------------------------------------------------------
  1411.  */
  1412. Boolean
  1413. VmCheckSharedSegment(procPtr,segPtr)
  1414.     Proc_ControlBlock    *procPtr;    /* Process to check. */
  1415.     Vm_Segment        *segPtr;    /* Pointer to shared segment. */
  1416. {
  1417.     Vm_SegProcList    *sharedSeg;
  1418.     Boolean     found=FALSE;
  1419.     /*
  1420.      * Check if segment is already on the process's list.
  1421.      */
  1422.     CHECK_SHM_MONITOR;
  1423.     dprintf("VmCheckSharedSegment: Checking if segment attached to process\n");
  1424.     LIST_FORALL(procPtr->vmPtr->sharedSegs,
  1425.         (List_Links *)sharedSeg) {
  1426.     if (sharedSeg->segTabPtr->segPtr == segPtr) {
  1427.         found = TRUE;
  1428.         break;
  1429.         }
  1430.     }
  1431.     if (found) {
  1432.     dprintf("it is\n");
  1433.     } else  {
  1434.     dprintf("it isn't\n");
  1435.     }
  1436.  
  1437.     return found;
  1438. }
  1439.  
  1440. /*
  1441.  *----------------------------------------------------------------------
  1442.  *
  1443.  * VmPrintSharedSegs --
  1444.  *
  1445.  *    Print info on the shared segments for a proc.
  1446.  *
  1447.  * Results:
  1448.  *    None.
  1449.  *
  1450.  * Side effects:
  1451.  *    Reads the shared memory data, so the SHM lock must be held.
  1452.  *
  1453.  *----------------------------------------------------------------------
  1454.  */
  1455. void
  1456. VmPrintSharedSegs(procPtr)
  1457.     Proc_ControlBlock    *procPtr;    /* Process to check. */
  1458. {
  1459.     Vm_SegProcList        *procListPtr;
  1460.     Vm_SharedSegTable    *segTabPtr;
  1461.  
  1462.     CHECK_SHM_MONITOR;
  1463.     dprintf("VmPrintSharedSegs: info for %x (%x)\n",(int)procPtr,
  1464.         (int)procPtr->processID);
  1465.     dprintf("  Shared Segment Table:\n");
  1466.     LIST_FORALL((List_Links *)&sharedSegTable,(List_Links *)segTabPtr) {
  1467.     dprintf("  entry: %x fileNumber: %d refcount: %d segPtr: %x segNum: %d\n",
  1468.         (int)segTabPtr,segTabPtr->fileNumber, segTabPtr->refCount,
  1469.         (int)segTabPtr->segPtr,segTabPtr->segPtr->segNum);
  1470.     }
  1471.     if (procPtr->vmPtr->sharedSegs == (List_Links *)NIL) {
  1472.     dprintf("  Process list: NIL\n");
  1473.     } else {
  1474.     dprintf("  Proc: %x (%x):\n",(int)procPtr,procPtr->processID);
  1475.     LIST_FORALL(procPtr->vmPtr->sharedSegs,(List_Links *)procListPtr) {
  1476.         dprintf("  fd: %d table: %x address: %x start: %x end: %x\n",
  1477.             (int)procListPtr->fd, procListPtr->segTabPtr,
  1478.             (int)procListPtr->addr, (int)procListPtr->mappedStart,
  1479.             (int)procListPtr->mappedEnd);
  1480.     }
  1481.     }
  1482. }
  1483.  
  1484. /*
  1485.  *----------------------------------------------------------------------
  1486.  *
  1487.  * Vm_CleanupSharedFile --
  1488.  *
  1489.  *    Delete segments associated with a file stream.
  1490.  *    This routine calls Vm_DeleteSharedSegment on the segments
  1491.  *    associated with the file stream.
  1492.  *
  1493.  * Results:
  1494.  *    None.
  1495.  *
  1496.  * Side effects:
  1497.  *    Shared segments are deleted.
  1498.  *    Uses the SHM lock.
  1499.  *
  1500.  *----------------------------------------------------------------------
  1501.  */
  1502. /*ARGSUSED*/
  1503. void
  1504. Vm_CleanupSharedFile(procPtr,streamPtr)
  1505.     Proc_ControlBlock    *procPtr;    /* Process with file. */
  1506.     Fs_Stream        *streamPtr;    /* Stream to remove. */
  1507. {
  1508.     Vm_SegProcList        *segPtr;
  1509.     Vm_SegProcList        *nextPtr;
  1510.     List_Links            *sharedSegs = procPtr->vmPtr->sharedSegs;
  1511.  
  1512.     LOCK_SHM_MONITOR;
  1513.     if (procPtr->vmPtr->sharedSegs != (List_Links *)NIL) {
  1514.     for (segPtr=(Vm_SegProcList *)List_First(sharedSegs);
  1515.         !List_IsAtEnd(sharedSegs,(List_Links *)segPtr);
  1516.         segPtr=nextPtr) {
  1517.         nextPtr = (Vm_SegProcList *)List_Next((List_Links *)segPtr);
  1518.         if (segPtr->stream==streamPtr) {
  1519.         dprintf("sharedSegment being deleted in Vm_CleanupSharedFile\n");
  1520. #if 0
  1521.         Vm_DeleteSharedSegment(procPtr,segPtr);
  1522. #else
  1523.         if (debugVmStubs) {
  1524.             printf("Vm_CleanupSharedFile: skipping segment delete\n");
  1525.         }
  1526. #endif
  1527.         if (sharedSegs == (List_Links *)NIL) {
  1528.             break;
  1529.         }
  1530.         }
  1531.     }
  1532.     }
  1533.     UNLOCK_SHM_MONITOR;
  1534. }
  1535.  
  1536. /*
  1537.  * ----------------------------------------------------------------------------
  1538.  *
  1539.  * Vm_CopySharedMem --
  1540.  *
  1541.  *     Copies shared memory data structures to handle a fork.
  1542.  *
  1543.  * Results:
  1544.  *     None.
  1545.  *
  1546.  * Side effects:
  1547.  *     The new process gets a copy of the shared memory structures.
  1548.  *
  1549.  * ----------------------------------------------------------------------------
  1550.  */
  1551. void
  1552. Vm_CopySharedMem(parentProcPtr, childProcPtr)
  1553.     Proc_ControlBlock    *parentProcPtr;    /* Parent process. */
  1554.     Proc_ControlBlock    *childProcPtr;    /* Child process. */
  1555. {
  1556.     Vm_Segment *segPtr;
  1557.     Vm_SegProcList *sharedSeg;
  1558.     Vm_SegProcList *parentSeg;
  1559.     LOCK_SHM_MONITOR;
  1560.     if (parentProcPtr->vmPtr->sharedSegs != (List_Links *)NIL) {
  1561.     childProcPtr->vmPtr->sharedSegs = (List_Links *)
  1562.         malloc(sizeof(Vm_SegProcList));
  1563.     List_Init((List_Links *)childProcPtr->vmPtr->sharedSegs);
  1564.     LIST_FORALL(parentProcPtr->vmPtr->sharedSegs,
  1565.         (List_Links *)parentSeg) {
  1566.         sharedSeg = (Vm_SegProcList *)malloc(sizeof(Vm_SegProcList));
  1567.         bcopy((Address)parentSeg, (Address)sharedSeg,
  1568.             sizeof(Vm_SegProcList));
  1569.         segPtr = sharedSeg->segTabPtr->segPtr;
  1570.         if(!VmCheckSharedSegment(childProcPtr, segPtr)) {
  1571.         Vm_SegmentIncRef(segPtr, childProcPtr);
  1572.         }
  1573.         segPtr->refCount++;
  1574.         List_Insert((List_Links *)sharedSeg,
  1575.             LIST_ATREAR((List_Links *)childProcPtr->vmPtr->sharedSegs));
  1576.     }
  1577.     VmMach_CopySharedMem(parentProcPtr, childProcPtr);
  1578.     }
  1579.     UNLOCK_SHM_MONITOR;
  1580. }
  1581.